#ifndef XLCOMM_NET_TCPCONNECTION_H_
#define XLCOMM_NET_TCPCONNECTION_H_

#include <atomic>
#include <memory>
#include <string>

#include "boost/any.hpp"
#include "xlcomm/define.h"
#include "xlcomm/net/buffer.h"
#include "xlcomm/net/callbacks.h"
#include "xlcomm/net/event_loop.h"
#include "xlcomm/net/inet_address.h"
#include "xlcomm/noncopyable.h"

namespace xlcomm {
namespace net {

class Socket;
class Channel;

// 一次TCP连接。它是不可再生的，一旦连接断开，这个TcpConnection对象就没啥用了
// 它没有发起连接的功能，构造函数参数是已经建立好连接的sockfd
// 一个TcpConnection自始至终都运行于一个EventLoop中
class XLCOMM_API TcpConnection
    : noncopyable,
      public std::enable_shared_from_this<TcpConnection> {
 public:
  enum State { kDisconnected, kConnecting, kConnected, kDisconnecting };

  TcpConnection(EventLoop* loop, const std::string& name, int sockfd,
                const InetAddress& local_addr, const InetAddress& peer_addr);
  ~TcpConnection();

  // 发送数据（线程安全）
  void Send(const void* data, size_t len);
  void Send(const char* str);
  void Send(const std::string& message);
  void Send(Buffer* buff);
  // void Send(std::string&& message);
  // void Send(Buffer&& buff);

  // 停止写入数据(half-close)。本函数能保证未发送的能发送完成，对方关闭前可读（线程安全）
  void Shutdown();
  // 强制关闭连接（线程安全）
  void ForceClose();

  // 禁用Nagle算法，避免连续发包出现延迟
  void SetTcpNoDelay(bool on);
  // 定期检查TCP连接是否还存在
  void SetKeepAlive(bool on);

  // 是否已连接
  bool IsConnected() const { return state_ == kConnected; }

  // 设置输出缓冲区(写缓冲区)高水位 及 到达高水位时的回调
  void SetOutbufHighWaterMark(const OutbufHighWaterCallback& cb,
                              size_t high_water_size) {
    outbuf_high_water_callback_ = cb;
    high_water_size_ = high_water_size;
  }

  void set_context(const boost::any& context) { context_ = context; }
  const boost::any& context() const { return context_; }
  boost::any* GetMutableContext() { return &context_; }

  EventLoop* loop() const { return loop_; }
  std::string name() const { return name_; }
  InetAddress local_addr() const { return local_addr_; }
  InetAddress peer_addr() const { return peer_addr_; }

  ///////////// 以下接口为TcpServer和TcpClient专用 /////////////

  // 接受到新连接时调用（应该只被调一次）
  void ConnectEstablished();
  // 销毁本连接时调用（应该只被调一次）
  void ConnectDestroyed();

  void set_connect_callback(const ConnectCallback& cb) {
    connect_callback_ = cb;
  }
  void set_disconnect_callback(const DisconnectCallback& cb) {
    disconnect_callback_ = cb;
  }
  void set_message_callback(const MessageCallback& cb) {
    message_callback_ = cb;
  }
  void set_write_complete_callback(const WriteCompleteCallback& cb) {
    write_complete_callback_ = cb;
  }
  // 用于通知TcpServer和TcpClient移除所持有的ConnectionPtr
  void set_close_callback(const CloseCallback& cb) { close_callback_ = cb; }

  ///////////// 以上接口为TcpServer和TcpClient专用 /////////////

 private:
  // 处理channel_可读事件
  void HandleRead(Timestamp recv_time);
  // 处理channel_可写事件
  void HandleWrite();
  // 处理channel_关闭事件
  void HandleClose();
  // 处理channel_出错事件
  void HandleError();
  // 在loop线程发送数据
  void SendInLoop(const std::string& message);
  void SendInLoop(const void* data, size_t len);
  // 在loop线程停止再写入数据
  void ShutdownInLoop();
  // 在loop线程强制关闭
  void ForceCloseInLoop();
  // 连接状态转字符串
  const char* StateToString() const;

  EventLoop* loop_;
  std::string name_;
  std::unique_ptr<Socket> socket_;
  std::unique_ptr<Channel> channel_;
  const InetAddress local_addr_;
  const InetAddress peer_addr_;
  std::atomic<State> state_;
  Buffer input_buffer_;
  Buffer output_buffer_;
  boost::any context_;

  ConnectCallback connect_callback_;
  DisconnectCallback disconnect_callback_;
  MessageCallback message_callback_;
  WriteCompleteCallback write_complete_callback_;
  OutbufHighWaterCallback outbuf_high_water_callback_;
  size_t high_water_size_;
  CloseCallback close_callback_;
};

}  // namespace net
}  // namespace xlcomm

#endif  // XLCOMM_NET_TCPCONNECTION_H_